package io.geekidea.boot.baiwang.service.impl;

import com.baiwang.open.entity.request.node.SOutputinvoiceInvoiceBalanceInfo;
import com.baiwang.open.entity.request.node.SOutputinvoiceInvoiceInvoiceDetail;
import com.baiwang.open.entity.response.SOutputinvoiceInvoiceResponse;
import com.baiwang.open.entity.response.SOutputinvoiceQueryResponse;
import com.baiwang.open.entity.response.node.SOutputinvoiceQuery;
import com.baiwang.open.entity.response.node.SOutputinvoiceQueryInvoiceOrderDetailDTO;
import com.baiwang.open.exception.BWOpenException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.geekidea.boot.baiwang.dto.common.Result;
import io.geekidea.boot.baiwang.dto.InvoiceRequest;
import io.geekidea.boot.baiwang.service.InvoiceService;
import io.geekidea.boot.baiwang.vo.QueryVo;
import io.geekidea.boot.util.StringUtils.TimeUtil;
import io.geekidea.boot.util.StringUtils.UrlToJson;
import io.geekidea.boot.util.baiwangApi.Invoice;
import io.geekidea.boot.util.baiwangApi.Query;
import io.geekidea.boot.util.baiwangApi.Retry;
import io.geekidea.boot.util.baiwangUtils.InvoiceUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


@Slf4j
@Service
public class InvoiceServiceImpl implements InvoiceService {
    // 最大查询次数
    private static final int MAX_QUERY_TIMES = 5;
    // 正常等待时间(毫秒)
    private static final int NORMAL_WAIT_TIME = 2000;
    // 重试后等待时间(毫秒)
    private static final int RETRY_WAIT_TIME = 1000;

    @Override
    public Result invoice(InvoiceRequest invoiceRequest)   {
        //开票明细集合
        List<SOutputinvoiceInvoiceInvoiceDetail> sOutputinvoiceInvoiceInvoiceDetails = new ArrayList<>();
        try {
            if (invoiceRequest.getInvoiceDetailList() != null && !invoiceRequest.getInvoiceDetailList().isEmpty()) {
                sOutputinvoiceInvoiceInvoiceDetails = convertJsonToInvoiceDetail(invoiceRequest.getInvoiceDetailList());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //差额凭证集合
        List<SOutputinvoiceInvoiceBalanceInfo> sOutputinvoiceInvoiceBalanceInfos = new ArrayList<>();
        try {
            if (invoiceRequest.getBalanceInfoList() != null && !invoiceRequest.getBalanceInfoList().isEmpty()) {
                sOutputinvoiceInvoiceBalanceInfos = convertJsonToBalanceInfoList(invoiceRequest.getBalanceInfoList());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        List<String> serialNos = new ArrayList<>();
        List<String> orderNos = new ArrayList<>();
        orderNos.add(invoiceRequest.getOrderNo());
        //需要发票明细
        String detailMark = "1";

        try {
            // 1. 发起发票开具请求
            SOutputinvoiceInvoiceResponse response = Invoice.issueAnInvoice(
                    invoiceRequest.getOrderNo(),
                    invoiceRequest.getInvoiceTerminalCode(),
                    invoiceRequest.getTaxationLabel(),
                    invoiceRequest.getInvoiceTypeCode(),
                    invoiceRequest.getOrderDateTime(),
                    invoiceRequest.getDrawer(),
                    invoiceRequest.getPayee(),
                    invoiceRequest.getChecker(),
                    invoiceRequest.getBuyerName(),
                    invoiceRequest.getPushEmail(),
                    invoiceRequest.getPushPhone(),
                    invoiceRequest.getTaxNo(),
                    invoiceRequest.getSellerAddress(),
                    invoiceRequest.getSellerPhone(),
                    invoiceRequest.getSellerBankName(),
                    invoiceRequest.getSellerBankNumber(),
                    invoiceRequest.getBuyerTaxNo(),
                    invoiceRequest.getBuyerBankNumber(),
                    invoiceRequest.getBuyerBankName(),
                    invoiceRequest.getBuyerPhone(),
                    invoiceRequest.getBuyerAddress(),

                    invoiceRequest.getDisplaySeller(),
                    invoiceRequest.getDisplaySellerAddTel(),
                    invoiceRequest.getDisplayBuyer(),
                    invoiceRequest.getDisplayBuyerAddTel(),

                    invoiceRequest.getOrderTotalAmount(),

                    sOutputinvoiceInvoiceBalanceInfos,
                    sOutputinvoiceInvoiceInvoiceDetails,

                    invoiceRequest.getPriceTaxMark(),
                    invoiceRequest.getRemarks()
            );
            // 等待1秒
            Thread.sleep(1000);
            // 获取流水号，但这只是表示请求已接受，不代表开票成功
            String serialNo = response.getResponse().getSerialNo();
            serialNos.add(serialNo);
            log.info("发票开具请求已接受，流水号: {}", serialNo);

            int currentQueryTimes = 0;

            // 2. 发票状态查询循环
            while (currentQueryTimes < MAX_QUERY_TIMES) {
                currentQueryTimes++;

                // 查询发票状态
                SOutputinvoiceQueryResponse queryResponse = Query.queryInvoice(
                        invoiceRequest.getTaxNo(),
                        serialNos,
                        orderNos,
                        detailMark
                );

                List<SOutputinvoiceQuery> responseList = queryResponse.getResponse();
                if (responseList == null || responseList.isEmpty()) {
                    log.warn("第{}次查询返回空结果，继续尝试", currentQueryTimes);
                    Thread.sleep(NORMAL_WAIT_TIME);
                    continue;
                }

                String status = InvoiceUtils.getFirstStatus(responseList);
                SOutputinvoiceQuery firstResponse = responseList.get(0);
                log.info("第{}次查询，开票状态：{}", currentQueryTimes, status);
                // 开票中、发票作废中
                switch (status) {
                    case "00":
                    case "04":
                        log.info("第{}次查询，开票（蓝票）处于中间状态{}，等待后重新查询", currentQueryTimes, status);

                        Thread.sleep(NORMAL_WAIT_TIME);
                        break;
                    // 开票成功
                    case "01":
//                        List<String> downLoadUrl = new ArrayList<>();
                        String downLoadUrlResult = UrlToJson.generateFileInfoJson(firstResponse.getPdfUrl(), "发票附件.pdf", firstResponse.getPdfUrl(), "");
                        String result = "[" + downLoadUrlResult + "]";
//                        downLoadUrl.add(downLoadUrlResult);
                        //转时间戳
                        String timeStamp = TimeUtil.convertToTimestamp(firstResponse.getInvoiceTime(), "yyyy-MM-dd HH:mm:ss");

                        String goodsName = null;
                        List<SOutputinvoiceQueryInvoiceOrderDetailDTO> invoiceDetailList = firstResponse.getInvoiceDetailList();
                        if (invoiceDetailList != null && !invoiceDetailList.isEmpty()) {
                            int size = invoiceDetailList.size();
                            if (size == 1) {
                                SOutputinvoiceQueryInvoiceOrderDetailDTO firstDetail = invoiceDetailList.get(0);
                                goodsName = "*"+firstDetail.getGoodsSimpleName()+"*-"+firstDetail.getGoodsName();
                            } else {
                                StringBuilder sb = new StringBuilder();
                                for (int i = 0; i < size; i++) {
                                    SOutputinvoiceQueryInvoiceOrderDetailDTO detail = invoiceDetailList.get(i);
                                    String name = detail.getGoodsName();
                                    if (name != null) {
                                        sb.append(name);
                                        if (i != size - 1) {
                                            sb.append("、");
                                        }
                                    }
                                }
                                goodsName = sb.toString();
                            }
                        }

                        QueryVo queryVo = new QueryVo(
                                firstResponse.getInvoiceBaseStatus(),
                                firstResponse.getStatusMessage(),
                                firstResponse.getErrorMessage(),
                                firstResponse.getInvoiceCode(),
                                firstResponse.getInvoiceNo(),
                                firstResponse.getDigitInvoiceNo(),
                                firstResponse.getPdfUrl(),
                                firstResponse.getOfdUrl(),
                                firstResponse.getXmlUrl(),
                                firstResponse.getSerialNo(),
                                firstResponse.getOrderNo(),

                                firstResponse.getInvoiceTotalPrice(),
                                firstResponse.getInvoiceTotalTax(),
                                firstResponse.getInvoiceTotalPriceTax(),
                                firstResponse.getInvoiceCheckCode(),
                                goodsName,
                                firstResponse.getBuyerName(),

                                result,
                                timeStamp
                        );
                        log.info("QueryVo", queryVo);
                        log.info("发票开具成功，流水号: {}", firstResponse.getSerialNo());
                        return Result.success(queryVo);
                    // 开票失败
                    case "02":
                        log.info("第{}次查询，开票失败-尝试重开发票", currentQueryTimes);

                        String isForceRepush = ""; // 非必填-强制开票标志:0-否(默认),1-是

                        // 调用重开发票接口，使用原流水号
                        Retry.retryInvoice(
                                invoiceRequest.getTaxNo(),
                                serialNo, // 使用原流水号
                                invoiceRequest.getOrderNo(),
                                invoiceRequest.getInvoiceTerminalCode(),
                                isForceRepush
                        );

                        // 重开后减少查询次数计数，给新请求留出时间
                        currentQueryTimes--;

                        // 重开后短暂等待再查询
                        Thread.sleep(RETRY_WAIT_TIME);
                        break;
                    // 发票已作废
                    case "03":
                        log.warn("发票已作废，流水号: {}", serialNo);
                        return Result.error("发票已作废！");

                    default:
                        log.warn("未知状态码: {}, 继续查询", status);
                        // 等待后继续查询
                        Thread.sleep(NORMAL_WAIT_TIME);
                }
            }

            //  超过最大查询次数仍未有最终状态
            log.error("发票处理超时，流水号: {}", serialNo);
            return Result.error("发票处理超时，请稍后手动查询状态");

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("发票处理流程被中断", e);
            return Result.error("发票处理被中断" + e.getMessage());
        } catch (BWOpenException e) {
            log.error("发票处理过程中发生异常", e);
            return Result.error(e.getMessage() + ":" + e.getSubMessage());
        }
    }

    public List<SOutputinvoiceInvoiceBalanceInfo> convertJsonToBalanceInfoList(String jsonStr) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(jsonStr, new TypeReference<List<SOutputinvoiceInvoiceBalanceInfo>>() {
        });
    }

    public List<SOutputinvoiceInvoiceInvoiceDetail> convertJsonToInvoiceDetail(String jsonStr) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(jsonStr, new TypeReference<List<SOutputinvoiceInvoiceInvoiceDetail>>() {
        });
    }
}